from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext
from nc_mlpa.mlpa.models import MpaArray
from ImpactAnalysis import AnalysisResult, CommercialResultsByPort, CommercialResultsForStudyRegion
from utilities import nc_constants, GetSpeciesByGroup, GetPortsByGroup

'''
Called from display_array_analysis 
'''        
def compile_array_results(array, group, port=None):
    from MpaAnalysis import get_mpa_results
    array_results = []
    #run analysis results for each mpa in the array
    mpas = array.mpa_set
    for mpa in mpas:
        if mpa.designation_id is not None: #ignore Stewardship Zones and other mpas that have no LOP
            mpa_results = get_mpa_results(mpa, group, port)
            array_results.append(mpa_results)
    return array_results

        
'''
Aggregates results and renders templates based on fishing group
Called from views.impact_analysis and print_array_report        
'''        
def display_array_analysis(request, group, array, port=None, template=None):
    from utilities import isCOM, isCPFV, isSWD, isKYK, isDIV, isPVT, ensure_proper_name
    group = ensure_proper_name(group)
    array_results = compile_array_results(array, group)
    if isCOM(group):
        #aggregate array results for commercial group
        aggregated_results = aggregate_com_array_results(array_results, group)
        #restructure into AnalysisResults data structure
        (analysis_results, port_impacts, studyregion_impacts) = restructure_aggregated_commercial_results(array, group, aggregated_results)
        if template is None:
            template = 'array_impact_analysis_com.html'
        return render_to_response(template, RequestContext(request, {'user_group': group, 'array':array, 'analysis_results': analysis_results, 'port_impacts': port_impacts, 'studyregion_impacts': studyregion_impacts}))  
    elif isCPFV(group):
        #aggregate array results for commercial passenger fishing vessel group
        aggregated_results = aggregate_cpfv_array_results(array_results, group)
        #restructure into AnalysisResults data structure
        analysis_results = restructure_aggregated_cpfv_results(array, group, aggregated_results)
        if template is None:
            template = 'array_impact_analysis_cpfv.html'
        return render_to_response(template, RequestContext(request, {'user_group': group, 'array':array, 'array_results': analysis_results}))  
    elif isSWD(group):
        #aggregate array results for edible seaweed group
        aggregated_results = aggregate_swd_array_results(array_results, group)
        #restructure into AnalysisResults data structure
        analysis_results = restructure_aggregated_swd_results(array, group, aggregated_results)
        if template is None:
            template = 'array_impact_analysis_swd.html'
        return render_to_response(template, RequestContext(request, {'user_group': group, 'array':array, 'array_results': analysis_results}))  
    else: #(must be Recreational)
        #aggregate array results for edible seaweed group
        aggregated_results = aggregate_rec_array_results(array_results, group)
        #restructure into AnalysisResults data structure
        analysis_results = restructure_aggregated_rec_results(array, group, aggregated_results)
        if template is None:
            template = 'array_impact_analysis_rec.html'
        if isDIV(group):
            group_abbr = 'div'
        elif isKYK(group):
            group_abbr = 'kyk'
        elif isPVT(group):
            group_abbr = 'pvt'
        return render_to_response(template, RequestContext(request, {'group_abbr': group_abbr, 'user_group': group, 'array':array, 'array_results': analysis_results}))  

'''
Organizes Commercial results into 
    a list of AnalysisResult objects, sorted by port (north to south), sorted by species (alphabetically)
    a list of CommercialResultsByPort objects, sorted by port
    and a CommercialResultsForStudyRegion object
Called from display_array_analysis
'''
def restructure_aggregated_commercial_results(array, group, aggregated_results):
    analysis_results = []
    port_impacts = []
    #compile lists of analysis results by port and port_impacts
    for port, species_results in aggregated_results.iteritems():
        port_results = []
        port_gross_impact = 0
        port_net_impact = 0
        species_list = []
        #prepare values for CommercialResultsByPort object (used for port_impacts and studyregion_impacts)
        #and create list of species level AnalysisResults for this port
        for species, results in species_results.iteritems():
            #special case for Urchin which needs to be split between Dive Captain and Walk-on Dive
            if 'Urchin' in species:
                result1 = AnalysisResult(id=array.id, type='array', group=group, port=port, species='Urchin (Dive Captain)', percOverallArea=results['Area'], percOverallValue=results['Value'])
                result2 = AnalysisResult(id=array.id, type='array', group=group, port=port, species='Urchin (Walk-on Dive)', percOverallArea=results['Area'], percOverallValue=results['Value'])
                port_results.append(result1)
                port_results.append(result2)
                if result1.GEI != '---':
                    port_gross_impact += result1.GEI + result2.GEI
                    port_net_impact += result1.NEI + result2.NEI
                    species_list.append('Urchin (Dive Captain)')
                    species_list.append('Urchin (Walk-on Dive)')
            else:
                result = AnalysisResult(id=array.id, type='array', group=group, port=port, species=species, percOverallArea=results['Area'], percOverallValue=results['Value'])
                port_results.append(result)
                if result.GEI != '---':
                    port_gross_impact += float(result.GEI)
                    port_net_impact += float(result.NEI)
                    species_list.append(species)
        port_totals = CommercialResultsByPort(port, port_gross_impact, port_net_impact, species_list)
        port_impacts.append( port_totals )
        #sort results by species name (alphabetically)
        port_results = sort_results_by_species(port_results)
        analysis_results.append(port_results)
    studyregion_impacts = CommercialResultsForStudyRegion(port_impacts)
    analysis_results = sort_results_by_port(analysis_results, group)
    port_impacts = sort_results_by_port(port_impacts)
    return analysis_results, port_impacts, studyregion_impacts
        
'''
Organizes Commercial Passenger Fishing Vessel results into a list of AnalysisResult objects, sorted by port
Called from display_array_analysis
'''
def restructure_aggregated_cpfv_results(array, group, aggregated_results):
    analysis_results = []
    for port, results in aggregated_results.iteritems():
        analysis_results.append(AnalysisResult(id=array.id, type='array', group=group, port=port, percOverallArea=results['Area'], percOverallValue=results['Value']))
    #sort results by port name (north to south)
    analysis_results = sort_results_by_port(analysis_results, group) 
    return analysis_results       
    
'''
Organizes Edible Seaweed results into a list of AnalysisResult objects, sorted by port, sorted by species
Called from display_array_analysis
'''
def restructure_aggregated_swd_results(array, group, aggregated_results):
    analysis_results = []
    for port, species_results in aggregated_results.iteritems():
        port_results = []
        for species, results in species_results.iteritems():
            port_results.append(AnalysisResult(id=array.id, type='array', group=group, port=port, species=species, percOverallArea=results['Area'], percOverallValue=results['Value']))
        #sort results by species name (alphabetically)
        port_results = sort_results_by_species(port_results)
        #port_results = roundPercentageValues(port_results, 1)  
        analysis_results.append(port_results)
    #sort results by port name (north to south)
    analysis_results = sort_results_by_port(analysis_results, group) 
    return analysis_results       
               
'''
Organizes Recreational results into a list of AnalysisResult objects, sorted by port, sorted by species
Called from display_array_analysis
'''
def restructure_aggregated_rec_results(array, group, aggregated_results):
    analysis_results = []
    for port, species_results in aggregated_results.iteritems():
        port_results = []
        for species, results in species_results.iteritems():
            port_results.append(AnalysisResult(id=array.id, type='array', group=group, port=port, species=species, percOverallArea=results['Area'], percOverallValue=results['Value']))
        #sort results by species name (alphabetically)
        port_results = sort_results_by_species(port_results)
        #port_results = roundPercentageValues(port_results, 1)  
        analysis_results.append(port_results)
    #sort results by port name (north to south)
    analysis_results = sort_results_by_port(analysis_results, group) 
    return analysis_results       

'''   
Aggregates array results for Commercial group 
This aggregation simply sums percentage area and percentage value results for each species (in each port)
Called from display_arrray_analysis
'''
def aggregate_com_array_results(array_results, group):
    aggregated_array_results = get_empty_array_results_dictionary(group)
    for mpa_results in array_results:
        for port in mpa_results:
            for result in port:
                if result.percOverallValue == '---':
                    pass
                elif aggregated_array_results[result.port][result.species]['Value'] == '---':
                    aggregated_array_results[result.port][result.species]['Value'] = float(result.percOverallValue)
                    aggregated_array_results[result.port][result.species]['Area'] = float(result.percOverallArea)
                else:
                    aggregated_array_results[result.port][result.species]['Value'] += result.percOverallValue
                    aggregated_array_results[result.port][result.species]['Area'] += result.percOverallArea
    return aggregated_array_results       
        

'''   
Aggregates array results for Commercial Passenger Fishing Vessel group 
This aggregation calculates the average percentage area and percentage value results for all species in each port
Called from display_arrray_analysis
'''
def aggregate_cpfv_array_results(array_results, group):
    aggregated_array_results = get_empty_array_results_dictionary(group)
    group_ports = GetPortsByGroup(group)
    #sum up the value percentages at each port, keeping track of the number of summations made
    for mpa_results in array_results:
        #port_counts is used for determining average gei% among all relevant species for each port 
        #(we only need to calculate port_counts for one mpa as it will be the same for each mpa)
        port_counts = dict( (port, 0) for port in group_ports)
        for port_results in mpa_results:
            for result in port_results:
                if result.percOverallValue == '---':
                    pass
                elif aggregated_array_results[result.port]['Value'] == '---':
                    aggregated_array_results[result.port]['Value'] = float(result.percOverallValue)
                    aggregated_array_results[result.port]['Area'] = float(result.percOverallArea)
                    port_counts[result.port] = 1
                else:
                    aggregated_array_results[result.port]['Value'] += result.percOverallValue
                    aggregated_array_results[result.port]['Area'] += result.percOverallArea
                    port_counts[result.port] += 1
    for port in group_ports:
        if aggregated_array_results[port]['Value'] != '---':
            aggregated_array_results[port]['Value'] /= port_counts[port]
    return aggregated_array_results       
    
'''   
Aggregates array results for Recreational groups
This aggregation simply sums percentage area and percentage value results for each species (in each port)
Called from display_arrray_analysis
'''
def aggregate_rec_array_results(array_results, group):
    aggregated_array_results = get_empty_array_results_dictionary(group)
    for mpa_results in array_results:
        for port_results in mpa_results:
            for result in port_results:
                if result.percOverallValue == '---':
                    pass
                elif aggregated_array_results[result.port][result.species]['Value'] == '---':
                    aggregated_array_results[result.port][result.species]['Value'] = float(result.percOverallValue)
                    aggregated_array_results[result.port][result.species]['Area'] = float(result.percOverallArea)
                else:
                    aggregated_array_results[result.port][result.species]['Value'] += result.percOverallValue
                    aggregated_array_results[result.port][result.species]['Area'] += result.percOverallArea
    return aggregated_array_results       
   
'''   
Aggregates array results for Seaweed group 
This aggregation simply sums percentage area and percentage value results for each species (in each port)
Called from display_arrray_analysis
'''
def aggregate_swd_array_results(array_results, group):
    aggregated_array_results = get_empty_array_results_dictionary(group)
    for mpa_results in array_results:
        for port_results in mpa_results:
            for result in port_results:
                if result.percOverallValue == '---':
                    pass
                elif aggregated_array_results[result.port][result.species]['Value'] == '---':
                    aggregated_array_results[result.port][result.species]['Value'] = float(result.percOverallValue)
                    aggregated_array_results[result.port][result.species]['Area'] = float(result.percOverallArea)
                else:
                    aggregated_array_results[result.port][result.species]['Value'] += result.percOverallValue
                    aggregated_array_results[result.port][result.species]['Area'] += result.percOverallArea
    return aggregated_array_results      
    
'''   
Sorts results by species name (alphabetical)
Called from various restructure_aggregated_<group name>_results methods
'''
def sort_results_by_species(results):   
    #sort results alphabetically by species name
    results.sort(key=lambda obj: obj.species)  
    return results
    
'''   
Sorts results by port name (north to south)
Called from various restructure_aggregated_<group name>_results methods
'''
def sort_results_by_port(results, group=None):
    from utilities import isCPFV
    #sort results by port name (north to south)
    if group is None:
        ports = GetPortsByGroup('Commercial')
    else:
        ports = GetPortsByGroup(group)
    count = 0
    #build a dictionary that maps each port (key), with an ordinal (value)
    ordering = {}
    for port in ports:
        count += 1
        ordering[port] = count
    #use that dictionary to order the results by port
    if group is None or isCPFV(group):
        results.sort(lambda x, y : cmp (ordering[x.port], ordering[y.port]))  
    else: 
        results.sort(lambda x, y : cmp (ordering[x[0].port], ordering[y[0].port]))
    return results
    
'''   
Creates an empty dictionary structure for a given group 
Called from various aggregate_<group name>_array_results methods
'''
def get_empty_array_results_dictionary(group):
    from utilities import isCOM, isCPFV, isSWD
    group_species = GetSpeciesByGroup(group)
    group_ports = GetPortsByGroup(group)
    initialValue = '---'
    initialArea = '---'
    if isCOM(group):
        empty_results = dict( (port, dict( (nc_constants.COMMERCIAL_SPECIES_DISPLAY[species], {'Value':initialValue, 'Area':initialArea}) for species in group_species)) for port in group_ports)
    elif isCPFV(group):
        empty_results = dict( (port, {'Value':initialValue, 'Area':initialArea}) for port in group_ports)
    elif isSWD(group):
        empty_results = dict( (port, {'Seaweed (Hand Harvest)': {'Value':initialValue, 'Area':initialArea}}) for port in group_ports) 
    else:
        empty_results = dict( (port, dict( (species, {'Value':initialValue, 'Area':initialArea}) for species in group_species)) for port in group_ports) 
    return empty_results

'''
Called from print_report (in views.py)
Compiles array results (a list of mpa results)
Returns rendering results from display_array_analysis
'''   
def print_array_report(request, array_id, group):
    from utilities import isCOM, isCPFV, isSWD, isKYK, isDIV, isPVT
    array = get_object_or_404(MpaArray, pk=array_id)
    mpas = array.mpa_set
    if isCOM(group):
        group_name = 'Commercial'
        group_abbr = group
    elif isCPFV(group):
        group_name = 'Commercial Passenger Fishing Vessel'
        group_abbr = group
    elif isSWD(group):
        group_name = 'Edible Seaweed'
        group_abbr = group
    elif isDIV(group):
        group_name = 'Recreational Dive'
        group_abbr = 'rec'
    elif isKYK(group):
        group_name = 'Recreational Kayak'
        group_abbr = 'rec'
    elif isPVT(group):
        group_name = 'Recreational Private Vessel'
        group_abbr = 'rec'
    template = 'printable_%s_array_report.html' % group_abbr
    return display_array_analysis(request, group_name, array, template=template)
